package com.parse.antlr.tree;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.runtime.debug.*;

import com.parse.antlr.tree.parsers.ANTLRv3Lexer;
import com.parse.antlr.tree.parsers.ANTLRv3Parser;
import com.parse.antlr.tree.parsers.ANTLRv3TreeParser;

/** Build either ASTs and, optionally, parse trees.  To also build
 *  parse trees, run antlr with -debug option on ANTLRv3.g
 *  and then uncomment the middle code section and comment out the
 *  first "build AST" only section.
 */
public class ANTLRv3TreeWalker{
	
	private static List<org.antlr.runtime.tree.Tree> variableDeclartorNodes = new ArrayList<org.antlr.runtime.tree.Tree>();
	private static List<String> tokenNodes = new ArrayList<String>();
	private static List<String> commentNodes = new ArrayList<String>();
	private static List<String> variableList = new ArrayList<String>();
	private static List<String> keywordList = new ArrayList<String>();
	private static final String[] antlrKeywords = { "options", "grammar", "output", "ASTLabelType", "tokens", "members", "grammarDef", 
													"tokensSpec", "tokenSpec", "attrScope", "action", "actionScopeName", "optionsSpec", "option", "optionValue",
													"rule", "scope", "ruleAction", "throwsSpec", "ruleScopeSpec", "block", "altList", "init", "alternative", 
													"exceptionGroup", "exceptionHandler", "finallyClause", "element", "elementNoOptionSpec", "atom", "treeSpec",
													"notSet", "after", "ebnf", "range", "terminal", "notTerminal", "ebnfSuffix", "rewrite", "rewrite_alternative",
													"options", "rewrite_tree_block", "rewrite_tree_alternative", "rewrite_tree_element", "rewrite_tree_atom",
													"rewrite_tree_ebnf", "rewrite_template", "rewrite_template_ref", "rewrite_indirect_template_head", 
													"rewrite_template_args","rewrite_template_arg", "id"};
	private static final Set<String> antlrKeywordSet = new HashSet<String>(Arrays.asList(antlrKeywords));
	
	
    public static void main(String args[]) throws Exception {
    	ANTLRFileStream input = new ANTLRFileStream(
    			"/Users/irimnoho/Documents/workspace/lang-parser/data/antlr/ANTLRv3.g");
        
        // BUILD AST
        ANTLRv3Lexer lex = new ANTLRv3Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lex);
        ANTLRv3Parser g = new ANTLRv3Parser(tokens);
        ANTLRv3Parser.grammarDef_return r = g.grammarDef();
        CommonTree t = (CommonTree)r.getTree();
//        System.out.println(t.toStringTree());
        
       
        
        /*
         // BUILD AST + PARSE TREES (needs ANTLR -debug option)
          */
//        ParseTreeBuilder builder = new ParseTreeBuilder(inputName);
//        System.out.println("parse tree: "+builder.getTree().toStringTree());
//        System.out.print("input:\n"+builder.getTree().toInputString());
         
        
        // WALK AST
        CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
        nodes.setTokenStream(tokens);
        ANTLRv3TreeParser walker = new ANTLRv3TreeParser(nodes);
        walker.grammarDef();
        
        printTree(t,1);
        
//        for(Tree variableTree : variableDeclartorNodes){
//			Tree variable = variableTree.getChild(0);
//			variableList.add(variable.toString());
//			//printTree(variableTree, 1);
//		}
		
		System.out.println("\n\n\nVariables: " + variableList);
		
		System.out.println("\n\n\n Keywords: " + keywordList);
		
		System.out.println("\n\n\nType: " + tokenNodes);
		
	    
		
//		 System.out.println("\n\n\nComments" + commentNodes.toString());
	        
        
        
    }
    
    public static void printTree(Tree t, int indent) {
        System.out.println(t.toString());
        printTreeHelper(t, indent);
    }

    private static void printTreeHelper(Tree t, int indent) {
    	
        if (t != null) {
            StringBuffer sb = new StringBuffer(indent);
            for (int i = 0; i < indent; i++)
                sb = sb.append("   ");
            for (int i = 0; i < t.getChildCount(); i++) {
            	int type = t.getChild(i).getType();
            	if(type == 29){
            		Tree variables = t.getChild(i);
            		while(variables.getChildCount() >0)
            			variables = variables.getChild(0);
            		variableList.add(variables.toString());
            	}
            	if(type == 54){
            		Tree tokenNode = t.getChild(i);
            		while(tokenNode.getChildCount() >0)
            			tokenNode = tokenNode.getChild(0);
            		//System.out.println("Type Child: "+ typeNode.toString());
            		tokenNodes.add(tokenNode.toString());
            	}
//            	if(type == ANTLRv3Lexer.DOC_COMMENT ||  type == ANTLRv3Lexer.SL_COMMENT || type == ANTLRv3Lexer.ML_COMMENT){
//            		Tree commentNode = t.getChild(i);
//            		while(commentNode.getChildCount() >0)
//            			commentNode = commentNode.getChild(0);
//            		
//            		//System.out.println("Type Child: "+ typeNode.toString());
//            		commentNodes.add(commentNode.toString());
//            		
//            	}

            	if(type == 59){
            		Tree keywordNode = t.getChild(i);
            		while(keywordNode.getChildCount() >0)
            			keywordNode = keywordNode.getChild(0);
            		//System.out.println("Type Child: "+ typeNode.toString());
            		keywordList.add(keywordNode.toString());
            	}
            	
                //if (t.getChild(i).getType()==4)
                System.out.println(sb.toString() + t.getChild(i).toString()
                + " [" + ANTLRv3Parser.tokenNames[type]
                + "]");
                printTreeHelper((CommonTree) t.getChild(i), indent + 1);
            }
        }
       
    }
}